﻿using System;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;

namespace RG.Common
{
    public static class TimeSpanExtensions
    {
        public static string ToShortString(this TimeSpan ts)
        {
            return (ts.Seconds == 0)
                       ? string.Format("{0:00}:{1:00}", ts.Hours, ts.Minutes)
                       : string.Format("{0:00}:{1:00}:{2:00}", ts.Hours, ts.Minutes, ts.Seconds);
        }

        public static string ToShortString(this TimeSpan? ts)
        {
            return ts.HasValue ? ts.Value.ToShortString() : string.Empty;
        }

        public static string ToShortTimeString(this DateTime? tm)
        {
            if (tm == null) return string.Empty;
            return (tm.Value.Second == 0)
                       ? string.Format("{0}:{1:D2}", tm.Value.Hour, tm.Value.Minute)
                       : string.Format("{0}:{1:D2}:{2:D2}", tm.Value.Hour, tm.Value.Minute, tm.Value.Second);
        }

        public static string ToShortString(this DateTime dt)
        {
            return string.Format("{0} {1}", dt.ToShortDateString(), dt.ToShortTimeString());
        }
        /// <summary>
        /// Парсинг времени в формате HH:MM
        /// Возвращает null, если формат ошибочен
        /// </summary>
        public static TimeSpan? ToTime(this string str)
        {
            if (str == null) return null;
            var match = time_rx1.Match(str);
            if (match.Success)
            {
                int h = Convert.ToInt32(match.Groups[1].Value), m = Convert.ToInt32(match.Groups[2].Value), s = Convert.ToInt32(match.Groups[3].Value);
                if (h >= 24 || m >= 60 || s >= 60) return null;
                return new TimeSpan(h, m, s);
            }
            match = time_rx2.Match(str);
            if (match.Success)
            {
                int h = Convert.ToInt32(match.Groups[1].Value), m = Convert.ToInt32(match.Groups[2].Value);
                if (h >= 24 || m >= 60) return null;
                return new TimeSpan(h, m, 0);
            }
            match = time_rx3.Match(str);
            if (match.Success)
            {
                int h = Convert.ToInt32(match.Groups[1].Value);
                if (h >= 24) return null;
                return new TimeSpan(h, 0, 0);
            }
            return null;
        }
        static readonly Regex time_rx1 = new Regex(@"^(\d?\d):(\d\d):(\d\d)$");
        static readonly Regex time_rx2 = new Regex(@"^(\d?\d):(\d\d)$");
        static readonly Regex time_rx3 = new Regex(@"^(\d?\d)$");
    }

    [DataContract]
    public class Interval<T>
    {
        [DataMember] 
        public T From { get; set; }
        [DataMember] 
        public T To { get; set; }
    }


    [DataContract]
    public class DatesRange
    {
        public static DatesRange FromOneDay(DateTime dateTime)
        {
            return new DatesRange(dateTime.Date, dateTime.Date.AddHours(23).AddMinutes(59).AddSeconds(59));
        }

        public DatesRange()
        {
        }

        public DatesRange(DateTime date)
        {
            minDate = date;
            maxDate = date;
        }

        public DatesRange(DateTime? min, DateTime? max)
        {
            minDate = min;
            maxDate = max;
        }

        public TimeSpan? Length
        {
            get
            {
                return minDate.HasValue && maxDate.HasValue
                    ? (maxDate - minDate)
                    : null;
            }
        }

        [DataMember] 
        public DateTime? minDate;
        [DataMember] 
        public DateTime? maxDate;


        public override string ToString()
        {
            if (minDate != null && maxDate != null)
                return string.Format("c {0} до {1}",minDate.Value.ToString("dd.MM.yyyy"),
                    maxDate.Value.ToString("dd.MM.yyyy")); 
            if(maxDate != null)
                return string.Format("до {0}",maxDate.Value.ToString("dd.MM.yyyy")); 
            if(minDate != null)
                return string.Format("с {0}", minDate.Value.ToString("dd.MM.yyyy"));
            return string.Empty;
        }

        public bool IsPeriod()
        {
            return minDate.HasValue && maxDate.HasValue && minDate.Value <= maxDate.Value;
        }
    }

    public static class DatesRangeExtension
    {
        public static bool IsBetween(this DatesRange dr, DateTime dateTime)
        {
            if (dr == null) return true;
            var minDate = dr.minDate;
            var maxDate = dr.maxDate;
            if (!minDate.HasValue && !maxDate.HasValue)
                return true;
            if (minDate.HasValue && !maxDate.HasValue)
                return minDate.Value < dateTime;
            if (!minDate.HasValue)
                return maxDate.Value > dateTime;
            return minDate.Value < dateTime && maxDate.Value > dateTime;
        }

        public static bool IsBetweenInclusive(this DatesRange dr, DateTime dateTime)
        {
            if (dr == null) return true;
            var minDate = dr.minDate;
            var maxDate = dr.maxDate;
            if (!minDate.HasValue && !maxDate.HasValue)
                return true;
            if (minDate.HasValue && !maxDate.HasValue)
                return minDate.Value <= dateTime;
            if (!minDate.HasValue)
                return maxDate.Value >= dateTime;
            return minDate.Value <= dateTime && maxDate.Value >= dateTime;
        }
    }

    public class pair<X,Y>
    {
        public X first;
        public Y second;

        public pair(X x, Y y)
        {
            first = x;
            second = y;
        }
    }

    public class troika<X,Y,Z>
    {
        public X first;
        public Y second;
        public Z third;

        public troika(X x, Y y, Z z)
        {
            first = x;
            second = y;
            third = z;
        }
    }
}